Skip to content

Copy, Move 與 RAII ​

C++ 用 destructor 自動釋放資源(RAII),但 class 持有 raw pointer 時,只寫 constructor / destructor 不夠。

Rule of Five ​

函數簽名
copy constructorC(const C&)
copy assignmentC& operator=(const C&)
move constructorC(C&&)
move assignmentC& operator=(C&&)
destructor~C()

編譯器自動生成的 copy 只複製指標 → 兩個物件指向同一塊記憶體 → double free。

Copy:copy-and-swap ​

cpp
IntBuff& operator=(const IntBuff& ib) {
    IntBuff tmp(ib);          // 可能 throw 的部分先做
    std::swap(arr, tmp.arr);  // 不會 throw 才改自己
    std::swap(sz, tmp.sz);
    return *this;
}

順便處理了 self-assignment 與 exception safety。

Move ​

  • r-value:只能放在等號右邊的值,例如 foo()、b + 1、99
  • T&& 綁定 r-value;std::move(x) 把 l-value 轉成 r-value reference
  • 實作 move:接手指標,並把來源設成「空」,避免重複釋放
cpp
IntBuff(IntBuff&& ib) noexcept : arr(ib.arr), sz(ib.sz) {
    ib.arr = nullptr;
    ib.sz = 0;
}

std::unique_ptr ​

一個 class 管理一個資源。成員改成 std::unique_ptr<int[]> 後:

  • 不用手寫 delete
  • move 直接 = default
  • copy 被禁止,需要時自己實作(new 一份再複製內容)
cpp
class IntBuff {
public:
    explicit IntBuff(size_t sz) : arr(std::make_unique<int[]>(sz)), sz(sz) {}
    IntBuff(const IntBuff& ib) : IntBuff(ib.sz) {
        std::copy(ib.arr.get(), ib.arr.get() + sz, arr.get());
    }
    IntBuff& operator=(const IntBuff& ib) {
        IntBuff tmp(ib);
        std::swap(*this, tmp);
        return *this;
    }
    IntBuff(IntBuff&&) noexcept = default;
    IntBuff& operator=(IntBuff&&) noexcept = default;

private:
    std::unique_ptr<int[]> arr;
    size_t sz = 0;
};

參考 ​

頁面歷史

Just observe 👀